﻿/*************************************************************************
 * Created by OhZee Creative, LLC
 * 2013
 * This code is licensed under Microsoft Public License (Ms-PL)
 * http://opensource.org/licenses/ms-pl
 * http://ozcontrols.codeplex.com/
 *************************************************************************/

namespace OhZeeCreative.UI.Controls
{
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;

#if SILVERLIGHT
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Shapes;
    using System.Windows.Media;
    using System.Windows.Data;
#endif
#if NETFX_CORE
    using Windows.Foundation;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using Windows.UI;
    using Windows.UI.Xaml.Shapes;
    using Windows.UI.Xaml.Data;
#endif

    /// <summary>
    /// RadialRepeater is a control that clones the content specified in the ItemTemplate as many times as specified and lays it out radially. The clones can easily be rotated to point to the center. An example use is for creating tickmarks around a gauge.
    /// </summary>
    [EditorBrowsableAttribute(EditorBrowsableState.Always)]
    [TemplatePart(Name = MultiRing.TEMPLATE_PART_grid, Type = typeof(Grid))]
	public sealed class MultiRing : Control
	{
        public const string TEMPLATE_PART_grid = "grid";
        private Grid grid;

        private Size lastSize = new Size();

        public static readonly DependencyProperty WeightsProperty = DependencyProperty.Register("Weights", typeof(string), typeof(MultiRing), new PropertyMetadata(null, new PropertyChangedCallback(WeightsChanged)));
        public static readonly DependencyProperty FillBrush1Property = DependencyProperty.Register("FillBrush1", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Red)));
        public static readonly DependencyProperty FillBrush2Property = DependencyProperty.Register("FillBrush2", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Orange)));
        public static readonly DependencyProperty FillBrush3Property = DependencyProperty.Register("FillBrush3", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Yellow)));
        public static readonly DependencyProperty FillBrush4Property = DependencyProperty.Register("FillBrush4", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Green)));
        public static readonly DependencyProperty FillBrush5Property = DependencyProperty.Register("FillBrush5", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Cyan)));
        public static readonly DependencyProperty FillBrush6Property = DependencyProperty.Register("FillBrush6", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Blue)));
        public static readonly DependencyProperty FillBrush7Property = DependencyProperty.Register("FillBrush7", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Magenta)));
        public static readonly DependencyProperty FillBrush8Property = DependencyProperty.Register("FillBrush8", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Purple)));
        public static readonly DependencyProperty FillBrush9Property = DependencyProperty.Register("FillBrush9", typeof(Brush), typeof(MultiRing), new PropertyMetadata(new SolidColorBrush(Colors.Black)));
        

        private static void WeightsChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            MultiRing ring = (MultiRing)o;
            ring.UpdateChildren();
        }

#if SILVERLIGHT
        public override void OnApplyTemplate()
#endif
#if NETFX_CORE
		protected override void OnApplyTemplate()
#endif
		{
            grid = this.GetTemplateChild(MultiRing.TEMPLATE_PART_grid) as Grid;
            this.UpdateChildren();
		}
				
		#region Properties for dependency properties

        [EditorBrowsable(EditorBrowsableState.Always)]
        public string Weights
        {
            get { return (string)GetValue(WeightsProperty); }
            set { SetValue(WeightsProperty, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #1
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush1
        {
            get { return (Brush)GetValue(FillBrush1Property); }
            set { SetValue(FillBrush1Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #2
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush2
        {
            get { return (Brush)GetValue(FillBrush2Property); }
            set { SetValue(FillBrush2Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #3
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush3
        {
            get { return (Brush)GetValue(FillBrush3Property); }
            set { SetValue(FillBrush3Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #4
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush4
        {
            get { return (Brush)GetValue(FillBrush4Property); }
            set { SetValue(FillBrush4Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #5
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush5
        {
            get { return (Brush)GetValue(FillBrush5Property); }
            set { SetValue(FillBrush5Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #6
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush6
        {
            get { return (Brush)GetValue(FillBrush6Property); }
            set { SetValue(FillBrush6Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #7
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush7
        {
            get { return (Brush)GetValue(FillBrush7Property); }
            set { SetValue(FillBrush7Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #8
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush8
        {
            get { return (Brush)GetValue(FillBrush8Property); }
            set { SetValue(FillBrush8Property, value); }
        }

        /// <summary>
        /// Gets or sets the fill brush for ring #9
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Always)]
        public Brush FillBrush9
        {
            get { return (Brush)GetValue(FillBrush9Property); }
            set { SetValue(FillBrush9Property, value); }
        }

		#endregion

        public MultiRing()
		{
            this.DefaultStyleKey = typeof(MultiRing);
            this.SizeChanged += (s, e) => { lastSize = e.NewSize; this.UpdateChildren(); };
		}

        private readonly char[] charSeperators = new char[] { ';' };
		
		private void UpdateChildren()
		{
			if (this.grid == null)
			{
				return;
			}

            this.grid.Children.Clear();

            if (string.IsNullOrEmpty(Weights))
            {
                return;
            }

            double[] weights;

            try
            {
                weights = Weights.Split(charSeperators, StringSplitOptions.RemoveEmptyEntries).Select(w => Convert.ToDouble(w)).ToArray();
            }
            catch
            {
                Debug.WriteLine("Error: MultiRing weights must be a semi-colon seperated list of double values");
                return;
            }

            double totalSum = weights.Sum();

            double fullWidth = lastSize.Width;
            double fullHeight = lastSize.Height;

            for (int childIndex = 0; childIndex < weights.Length; childIndex++)
			{
                double remainingSum = weights.Skip(childIndex).Sum();
                
                double weight = (remainingSum / totalSum);
                Ellipse ellipse = new Ellipse() { Width = fullWidth * weight, Height = fullHeight * weight };
                BindEllipseBrush(ellipse, childIndex);
				this.grid.Children.Add(ellipse);
			}            
		}

        private void BindEllipseBrush(Ellipse ellipse, int index)
        {
            if (index >= 0 && index < 9)
            {
                string bindingPath = "FillBrush" + (index + 1).ToString();

                ellipse.SetBinding(Ellipse.FillProperty, new Binding() { Path = new PropertyPath(bindingPath), Source = this });
            }
        }
	}
}
